package zap

import (
	"io"

	"gitee.com/mkwchecking/sr-core/log/ilog"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var _ ilog.Logger = (*Zap)(nil)

func init() {
	ilog.RegisterLogHandler("zap", New)
}

func New(cfg *ilog.Config, writer ilog.Writer) (ilog.Logger, error) {

	zapWriter := zapcore.AddSync(writer)
	core := newZapCore(zapLevel(cfg.Level), cfg.Format, zapWriter)
	logger := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(cfg.CallSkip))

	return &Zap{
		writer:  writer,
		handler: logger,
	}, nil
}

func newZapCore(level zapcore.Level, format ilog.Format, writer zapcore.WriteSyncer) zapcore.Core {
	var encoder zapcore.Encoder
	switch format {
	case ilog.JsonFormat:
		encoder = zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
	default:
		encoder = zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
	}

	return zapcore.NewCore(
		encoder,
		zapcore.AddSync(writer),
		level,
	)
}

type Zap struct {
	handler *zap.Logger
	writer  io.Writer
}

func (z *Zap) Writer() io.Writer {
	return z.writer
}

func (z *Zap) Trace(msg string, kvs ...interface{}) {
	z.handler.Debug(msg, kvsToZapFields(kvs...)...)
}

// Debug implements log.Logger.
func (z *Zap) Debug(msg string, kvs ...interface{}) {
	z.handler.Debug(msg, kvsToZapFields(kvs...)...)
}

// Error implements log.Logger.
func (z *Zap) Error(msg string, kvs ...interface{}) {
	z.handler.Error(msg, kvsToZapFields(kvs...)...)
}

// Fatal implements log.Logger.
func (z *Zap) Fatal(msg string, kvs ...interface{}) {
	z.handler.Fatal(msg, kvsToZapFields(kvs...)...)
}

// Info implements log.Logger.
func (z *Zap) Info(msg string, kvs ...interface{}) {
	z.handler.Info(msg, kvsToZapFields(kvs...)...)
}

// Log implements log.Logger.
func (z *Zap) Log(level ilog.Level, kvs ...interface{}) error {
	z.handler.Log(zapLevel(level), "", kvsToZapFields(kvs...)...)
	return nil
}

// Warn implements log.Logger.
func (z *Zap) Warn(msg string, kvs ...interface{}) {
	z.handler.Warn(msg, kvsToZapFields(kvs...)...)
}

// With implements log.Logger.
func (z *Zap) With(kvs ...interface{}) ilog.Logger {
	return &Zap{
		handler: z.handler.With(kvsToZapFields(kvs...)...),
		writer:  z.writer,
	}
}
